////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxsession.h
/// @brief Declarations for Session class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef CAMXSESSION_H
#define CAMXSESSION_H

#include "camxchicontext.h"
#include "camxhwdefs.h"

// NOWHINE FILE NC003a: Long existing structures. To be cleaned up at a later point
// NOWHINE FILE NC008:  Long existing structures. To be cleaned up at a later point
// NOWHINE FILE DC012:  Long existing structures. To be cleaned up at a later point

CAMX_NAMESPACE_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Forward Declaration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class  ChiContext;
class  Condition;
class  DeferredRequestQueue;
class  Device;
class  HAL3Queue;
class  MetadataPool;
class  Mutex;
class  Pipeline;
class  CmdBuffer;
class  CmdBufferManager;

enum class Format;

struct BufferRequirement;
struct PipelineProcessRequestData;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const UINT32 NotificationListSize       = RequestQueueDepth * 3; ///< Max 3 times the Q depth for notification messages
static const UINT32 OutputStreamBufferListSize = RequestQueueDepth * MaxNumOutputBuffers * 3; ///< Max 3 times the Q depth
                                                                                              ///  for output stream buffers
static const UINT32 InvalidPipelineIndex       = 0xFFFFFFFF;            ///< Invalid pipeline index
static const UINT32 MaxRealTimePipelines       = 2;                     ///< Max real time pipelines in one session
static const UINT32 MaxNodesPerUsecase         = 32;
static const UINT32 MaxPorts                   = 16;
static const UINT32 MaxBufferMemFlags          = 16;
static const UINT32 MaxQueueDepth              = RequestQueueDepth * 8; ///< Max 8 times of the queue depth
static const UINT32 EmptyMetadataEntryCapacity = 1024;                  ///< Replaced metadata entry capacity
static const UINT32 EmptyMetadataDataCapacity  = 10 * 1024;             ///< Replaced metadata data capacity

enum class BufferMemFlag
{
    Hw           = 0,                ///< Hardware  access
    Protected    = 1,                ///< Protected access
    CmdBuffer    = 2,                ///< CmdBuffer access
    UMDAccess    = 3,                ///< UMD       access
    Cache        = 4,                ///< Cached    access
    PacketBuffer = 5,                ///< Packet    access
    KMDAccess    = 6,                ///< KMD       access
    Max          = 7,                ///< Max
};

/// @todo (CAMX-1512) Add static asserts
enum class NodeClass
{
    Default = 0,                             ///< Default node type
    Bypass  = 1,                             ///< Bypass node
    Inplace = 2                              ///< Inplace node
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NodePropertyType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct NodePropertyType
{
    UINT32          NodePropertyId;
    CHAR*           NodePropertyValue;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NodeInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct NodeInfo
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NodeProperty - Array
    /// Min Length:    0
    /// Max Length:    Unbounded
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32            NodePropertyCount;
    UINT32            NodePropertyID;
    NodePropertyType* NodeProperty;
    CHAR*             NodeName;
    UINT32            NodeId;
    CHAR*             NodeInstance;
    UINT32            NodeInstanceId;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NodesListInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct NodesListInfo
{

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Node - Array
    /// Min Length:    1
    /// Max Length:    Unbounded
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32    NodeCount;
    UINT32    NodeID;
    NodeInfo* Node;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// PortInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct PortInfo
{
    CHAR*   PortName;
    UINT32  PortId;
    UINT32  PortSrcTypeIdExists;
    UINT32  PortSrcTypeIdID;
    UINT32  PortSrcTypeId;
    UINT32  BypassPortSrcIdCount;
    UINT32  BypassPortSrcIdID;
    UINT32* BypassPortSrcId;
    CHAR*   NodeName;
    UINT32  NodeId;
    CHAR*   NodeInstance;
    UINT32  NodeInstanceId;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// LinkPropertiesInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct LinkPropertiesInfo
{
    BOOL BatchMode;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// BufferPropertiesInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct BufferPropertiesInfo
{
    Format           BufferFormat;
    UINT32           BufferSizeExists;
    UINT32           BufferSizeID;
    UINT32           BufferSize;
    UINT32           BufferImmediateAllocCount;
    UINT32           BufferQueueDepth;
    UINT32           BufferHeap;
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// BufferFlags - Array
    /// Min Length:    1
    /// Max Length:    Unbounded
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32           BufferFlagsCount;
    UINT32           BufferFlagsID;
    BufferMemFlag*   BufferFlags;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// LinkInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct LinkInfo
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// LinkProperties - Optional
    /// Min Length:    0
    /// Max Length:    1
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32                LinkPropertiesExists;
    UINT32                LinkPropertiesID;
    LinkPropertiesInfo    LinkProperties;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SrcPort
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PortInfo              SrcPort;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DstPort - Array
    /// Min Length:    1
    /// Max Length:    Unbounded
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32                DstPortCount;
    UINT32                DstPortID;
    PortInfo*             DstPort;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// BufferProperties - Optional
    /// Min Length:    0
    /// Max Length:    1
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32                BufferPropertiesExists;
    UINT32                BufferPropertiesID;
    BufferPropertiesInfo  BufferProperties;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// PortLinkage
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct PortLinkage
{
    UINT32               SourceNodeExists;
    UINT32               SourceNodeID;
    CHAR*                SourceNode;
    UINT32               SourceNodeInstanceExists;
    UINT32               SourceNodeInstanceID;
    CHAR*                SourceNodeInstance;
    UINT32               TargetNameExists;
    UINT32               TargetNameID;
    CHAR*                TargetName;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TargetDirection - Optional
    /// Min Length:    0
    /// Max Length:    1
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32               TargetDirectionExists;
    UINT32               TargetDirectionID;
    ChiStreamType        TargetDirection;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Link - Array
    /// Min Length:    1
    /// Max Length:    Unbounded
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32               LinkCount;
    UINT32               LinkID;
    LinkInfo*            Link;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// PipelineInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct PipelineInfo
{
    CHAR*         PipelineName;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NodesList
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    NodesListInfo NodesList;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PortLinkages
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PortLinkage   PortLinkages;
};


/// @brief Input port info based on XML
struct InputPortInfo
{
    CHAR*                   pPortName;                ///< Input port name
    UINT                    portId;                   ///< Input port Id
    UINT                    parentOutputPortId;       ///< Parent output port id
    UINT                    parentNodeIndex;          ///< Index of the parent node
    UINT                    portSourceTypeId;         ///< Port source type id

    union Flags
    {
        struct
        {
            BIT isSourceBuffer              : 1;  ///< Node with a source port that inputs a buffer
            BIT reserved                    : 31; ///< Reserved
        };

        UINT value;
    } flags;
};

/// @brief Input ports list based on XML
struct InputPorts
{
    UINT            numPorts;               ///< Number of ports
    InputPortInfo   portInfo[MaxPorts];     ///< Individual port info
};

/// @brief Link Properties
struct LinkProperties
{
    BOOL isBatchMode;                       ///< Batch mode indicator
};

/// @brief Buffer Properties
struct LinkBufferProperties
{
    Format         format;                          ///< Format
    UINT32         sizeBytes;                       ///< Size in bytes
    UINT32         immediateAllocCount;             ///< Count of buffers to allocate immediately
    UINT32         queueDepth;                      ///< Number of buffer allocations for the link
    UINT32         heap;                            ///< Buffer heap
    UINT           numMemFlags;                     ///< Number of mem flags
    BufferMemFlag  memFlags[MaxBufferMemFlags];     ///< Mem flags
};

/// @brief Port Link Information
struct PortLink
{
    UINT                 numInputPortsConnected;    ///< Number of inputs connected to this output port
    LinkProperties       linkProperties;            ///< Properties of the link itself
    LinkBufferProperties linkBufferProperties;      ///< Properties of the buffer associated with the link
};

/// @brief Output port info based on XML
struct OutputPortInfo
{
    PortLink portLink;                  ///< Info about the link
    CHAR*    pPortName;                 ///< Port Name
    UINT     portId;                    ///< Port Id
    UINT     portSourceTypeId;          ///< Port source type id
    UINT     numSourceIdsMapped;        ///< number of source port Ids mapped
    UINT*    pMappedSourcePortIds;      ///< pointer to the source port Ids mapped for bypass

    union Flags
    {
        struct
        {
            BIT isSinkBuffer    : 1;    ///< Node with a sink port that outputs a buffer
            BIT isSinkNoBuffer  : 1;    ///< Node with a sink port that does not output a buffer
            BIT reserved        : 30;   ///< Reserved
        };

        UINT value;                     ///< Value of the union
    } flags;
};

/// @brief Output ports list based on XML
struct OutputPorts
{
    UINT           numPorts;              ///< Number of ports
    OutputPortInfo portInfo[MaxPorts];    ///< Individual port info
};

/// @brief node property
struct PerNodeProperty
{
    UINT32 id;                            ///< ID of the property
    VOID*  pValue;                        ///< Pointer to data. Type dependent on ID
};

/// @brief Per node info based on XML
struct PerNodeInfo
{
    NodeInfo*        pNodeInfo;             ///< Node info coming from XML parser
    CHAR*            pNodeName;             ///< Node name
    CHAR*            pInstanceName;         ///< Node instance id
    UINT             nodePropertyCount;     ///< Node property count
    PerNodeProperty* pNodeProperties;       ///< Properties associated with the node
    UINT             nodeId;                ///< Node Id
    UINT             instanceId;            ///< Instance Id
    NodeClass        nodeClass;             ///< Node class, bypassable node or default node
    InputPorts       inputPorts;            ///< Input ports
    OutputPorts      outputPorts;           ///< Output ports
};

/// @brief Per pipeline info based on XML
struct PerPipelineInfo
{
    UINT         numNodes;                          ///< Number of nodes in the topology matching the usecase
    PerNodeInfo  nodeInfo[MaxNodesPerUsecase];      ///< Individual node info
};

/// @brief Node Properties
/// @todo (CAMX-1512) Better way to handle this
struct NodePropertyHandle
{
    VOID*  pNodeProperties;             ///< Properties associated with the node
    UINT32 nodeId;                      ///< Node identifier
    UINT32 nodeInstanceId;              ///< Node instance identifier
};

/// @brief Pipeline output data
struct PipelineOutputData
{
    ChiLinkNodeDescriptor nodePort;                                 ///< Node/port with which this output is associated with
    ChiStreamWrapper*     pOutputStreamWrapper;                     ///< Output buffer descriptor
};

/// @brief Sensor info
struct SensorInfo
{
    UINT32            cameraId;                                    ///< CameraId
    ChiSensorModeInfo sensorMode;                                  ///< Mode info
};

/// @brief Pipeline input data, some of which is given at session create time along with the pipeline descriptor
///        Session create time data: sensorInfo / inputstreamWrapper+isWrapperOwner
struct PipelineInputData
{
    ChiLinkNodeDescriptor nodePort;                                 ///< Node/port with which this input is associated with

    union
    {
        ChiBufferOptions bufferOptions;                             ///< Input buffer options for the input port
        SensorInfo       sensorInfo;                                ///< Sensor info
    };

    ChiStreamWrapper*     pInputStreamWrapper;                      ///< App selected input buffer descriptor
    BOOL                  isWrapperOwner;                           ///< Is the pipeline descriptor the creator of this wrapper
                                                                    ///  so that it knows whether to destroy it or not
};

/// @brief Pipeline descriptor flags
union PipelineDescriptorFlags
{
    struct
    {
        BIT isRealTime      : 1;                                        ///< Is this a real time pipeline
        BIT isSensorInput   : 1;                                        ///< Is the pipeline's input sensor
        BIT isSecureMode    : 1;                                        ///< Mode of pipeline Secure/Non-secure
        BIT isTorchWidget   : 1;                                        ///< Is the torch widget mode
        BIT isHFRMode       : 1;                                        ///< Is HFR mode.
        BIT reserved        : 27;                                       ///< Reserved bits
    };

    UINT32 allFlagsValue;
};

/// @brief Pipeline descriptor handle used to describe a pipeline
struct PipelineDescriptor
{
    PerPipelineInfo         pipelineInfo;                               ///< Pipeline info that will be used to create the
                                                                        ///  actual pipeline object
    UINT                    numOutputs;                                 ///< Number of outputs (<= MaxPipelineOutputs)
    PipelineOutputData      outputData[MaxPipelineOutputs];             ///< Output data
    UINT                    numInputs;                                  ///< Number of inputs  (<= MaxPipelineInputs)
    PipelineInputData       inputData[MaxPipelineInputs];               ///< Input data for this pipeline
    PipelineDescriptorFlags flags;                                      ///< Flags
    UINT                    numBatchedFrames;                           ///< Number of framework frames batched
    UINT                    maxFPSValue;                                ///< maxFPSValue info of batched frames
    UINT32                  cameraId;                                   ///< Camera Id of pipeline
};

/// @brief Pipeline finalization data needed for pipeline defer finalization
struct PipelineDeferredFinalizeData
{
    UINT32 pipelineResourcePolicy;     ///< pipeline resource policy
};

/// @brief Session pipeline data containing information pertaining to the session only
struct SessionPerPipelineData
{
    PipelineDescriptor*          pPipelineDescriptor;  ///< Complete copy of what the API passes in
                                                       ///  (no reference to app memory)
    Pipeline*                    pPipeline;            ///< Pipeline object
    PipelineDeferredFinalizeData pipelineFinalizeData; ///< Pipeline finalize data needed for finalize
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Type Definitions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// @brief Combine error and result status codes for easy processing in the HAL
enum class ResultType
{
    EarlyMetadataOK,///< Metadata result component looks good
    MetadataOK,     ///< Metadata result component looks good
    BufferOK,       ///< Buffer result component looks good
    MetadataError,  ///< Metadata result component is in error
    BufferError,    ///< Buffer result component is in error
    DeviceError,    ///< Equivalent to MessageCodeDevice
    RequestError,   ///< Equivalent to MessageCodeRequest
    Invalid         ///< Max out
};

/// @brief Holder structure to store a result per pipeline request
struct ResultHolder
{
    UINT32                  sequenceId;                              ///< ID assigned for this result
    UINT32                  numOutBuffers;                           ///< Expected number of Output buffers of this result
    BOOL                    isAlive;                                 ///< Is alive
    UINT32                  numInBuffers;                            ///< Expected number of Input buffers of this result
    BOOL                    addNoMore;                               ///< DO NOT add any more result component
    UINT32                  pendingMetadataCount;                    ///< Outstanding metadata count for this result
    BOOL                    tentativeMetadata;                       ///< For offline PCRs, we may not have result metadata
    ChiMessageDescriptor*   pMetadataError;                          ///< Placeholder for metadata result if in error
    Metadata*               pMetadata[MaxPartialMetadataHAL];        ///< Placeholder for good metadata result
    UINT32                  metadataCbIndex;                         ///< Next index where we can the slot the metadata to
    VOID*                   pPrivData;                               ///< Result private data

    struct BufferResult
    {
        ChiStream*            pStream;                          ///< O/P Stream pointer to which this buffer belongs
        ChiStreamBuffer*      pBuffer;                          ///< Placeholder for good output buffer result
        ChiMessageDescriptor* pBufferError;                     ///< Placeholder for output buffer if in error
        BOOL                  error;                            ///< TRUE if this buffer is in an error state
        BOOL                  valid;                            ///< Flag for buffer is invalid or not
    } bufferHolder[MaxNumOutputBuffers];                        ///< Placeholder for result buffers

    struct InputBufferInfo
    {
        ChiStream*       pStream;                        ///< I/P Stream pointer to which this buffer belongs
        ChiStreamBuffer* pBuffer;                        ///< Placeholder for input buffer
    } inputbufferHolder[MaxNumInputBuffers];                    ///< Placeholder for input buffers
};

/// @brief Holder structure to store a result per session request
struct SessionResultHolder
{
    ResultHolder    resultHolders[MaxPipelinesPerSession];  ///< result holder per pipeline request
    UINT32          numResults;                             ///< NUmber of pipeline result holders
};


/// @brief Stream buffers used to convey the result of a capture request
/// @note The size of the array in the structure is sufficient to handle max outstanding requests i.e. pipeline depth. So there
///       should never be a case where we run out of result stream buffers.
struct ResultStreamBuffers
{
    ChiStreamBuffer resultStreamBuffer[OutputStreamBufferListSize]; ///< Stream buffers
    UINT            freeIndex;                                      ///< Next free element in the array
};

/// @brief Notify messages used to convey generic messages (type "ChiMessageType")
/// @note The size of the array in the structure is sufficient to handle max outstanding requests i.e. pipeline depth. So there
///       should never be a case where we run out of notify message structures.
struct NotifyMessages
{
    ChiMessageDescriptor notifyMessage[NotificationListSize];           ///< Stream buffers
    UINT                 freeIndex;                                     ///< Next free element in the array
};

/// @brief Data required for creating a Pipeline
struct PipelineData
{
    PipelineDescriptor*   pPipelineDescriptor;                     ///< Pipeline descriptor
    ChiPipelineInputInfo* pChiPipelineInputInfo;                   ///< Chi pipeline input info
};

/// @brief Data required for creating a Session
struct SessionCreateData
{
    HwContext*       pHwContext;                                   ///< Context to which this session is associated with
    ChiContext*      pChiContext;                                  ///< CHI Context
    ThreadManager*   pThreadManager;                               ///< ThreadManager
    ChiPipelineInfo* pPipelineInfo;                                ///< Pipeline Info
    UINT             numPipelines;                                 ///< Number of pipeline handles being passed in
    UINT             usecaseNumBatchedFrames;                      ///< Number of frames batched
    ChiCallBacks*    pChiAppCallBacks;                             ///< Result callbacks made into the Chi app
    VOID*            pPrivateCbData;                               ///< Private data
};

/// @brief Overall callback structure used between Pipeline and Session
struct ResultsData
{
    CbType  type;                       ///< One of the different callback types
    UINT    pipelineIndex;              ///< Pipeline index in the session

    union
    {
        CbPayloadError      error;      ///< Error payload
        CbPayloadAsync      async;      ///< Async payload
        CbPayloadSof        sof;        ///< Sof payload
        CbPayloadMetadata   metadata;   ///< Metadata payload
        CbPayloadBuffer     buffer;     ///< Buffer payload
    } cbPayload;                        ///< One of the Callback payloads

    VOID* pPrivData;                    ///< private data for result
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// GetPipelineDescriptor
///
/// @brief  Get the Pipeline descriptor pointer
///
/// @param  hPipelineDescriptor Pipeline descriptor pointer
///
/// @return Pipeline descriptor pointer
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CAMX_INLINE PipelineDescriptor* GetPipelineDescriptor(
    CHIPIPELINEDESCRIPTOR hPipelineDescriptor)
{
    CAMX_ASSERT(NULL != hPipelineDescriptor);

    return reinterpret_cast<PipelineDescriptor*>(hPipelineDescriptor);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief  Session contains information about pipelines and requests/results related to them
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Session
{
public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyResult
    ///
    /// @brief  Pipelines notifies about the results via this interface
    ///
    /// @param  pResultsData Structure containing the results data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NotifyResult(
        ResultsData* pResultsData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessCaptureRequest
    ///
    /// @brief  This method is used by the application framework to send a new capture request
    ///
    /// @param  pCaptureRequests    The metadata and input/output buffers to use for the capture request.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessCaptureRequest(
         const ChiPipelineRequest* pCaptureRequests);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StreamOn
    ///
    /// @brief  StreamOn the hardware using the pipeline handle
    ///
    /// @param  hPipelineDescriptor Pipeline Descriptor to which the request is issued
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult StreamOn(
        CHIPIPELINEHANDLE hPipelineDescriptor);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StreamOff
    ///
    /// @brief  StreamOff the hardware using the pipeline handle
    ///
    /// @param  hPipelineDescriptor Pipeline Descriptor to which the request is issued
    /// @param  modeBitmask         Deactivate mode bitmask
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult StreamOff(
        CHIPIPELINEHANDLE           hPipelineDescriptor,
        CHIDEACTIVATEPIPELINEMODE   modeBitmask);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FlushRequests
    ///
    /// @brief  Flushes outstanding requests from queue
    ///
    /// @param  isForced  TRUE or FALSE
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult FlushRequests(
        BOOL isForced);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetFlushStatus
    ///
    /// @brief  Get the current flush status of the HAL3Device
    ///
    /// @return TRUE or FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL GetFlushStatus()
    {
        return static_cast<BOOL>(CamxAtomicLoadU8(&m_aFlushingPipeline) != FALSE);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetFlushSessionStatus
    ///
    /// @brief  Get the current flush session status of the HAL3Device
    ///
    /// @return TRUE or FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL GetFlushSessionStatus()
    {
        return static_cast<BOOL>(CamxAtomicLoadU8(&m_aFlushingSession) != FALSE);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CanRequestProceed
    ///
    /// @brief  Push an incoming request to the request queue till space is available or there is device error
    ///
    /// @param  pRequest The incoming request
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CanRequestProceed(
        const ChiCaptureRequest* pRequest);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// UpdateMultiRequestSyncData
    ///
    /// @brief  Push an incoming request to the request queue till space is available or there is device error
    ///
    /// @param  pRequest The incoming request
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID UpdateMultiRequestSyncData(
        const ChiPipelineRequest* pRequest);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPipelineIndex
    ///
    /// @brief  Get pipeline index by pipeline descriptor
    ///
    /// @param  hPipelineDescriptor pipeline descriptor
    ///
    /// @return index of pipeline
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32 GetPipelineIndex(
        CHIPIPELINEHANDLE hPipelineDescriptor)
    {
        UINT32 pipelineIndex = InvalidPipelineIndex;
        UINT32 index;
        if (m_numPipelines >= MaxPipelinesPerSession)
        {
            return pipelineIndex;
        }
        for (index = 0; index < m_numPipelines; index++)
        {
            if (hPipelineDescriptor == m_pipelineData[index].pPipelineDescriptor)
            {
                   // found corresponding pipeline can use index to get to it
                pipelineIndex = index;
                break;
            }
        }
        return pipelineIndex;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CheckValidInputRequest
    ///
    /// @brief  Check if the incoming request is well formed and valid
    ///
    /// @param  pRequest    Incoming request
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CheckValidInputRequest(
        const ChiCaptureRequest* pRequest
        ) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WaitOnAcquireFence
    ///
    /// @brief  Wait on the acquire fence of all HAL output buffers before accepting a request
    ///
    /// @param  pRequest The request to wait on
    ///
    /// @return CamxResultSuccess if wait is succesful on all buffers, CamxResultEFailed otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult WaitOnAcquireFence(
        const ChiCaptureRequest* pRequest);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessRequestWhileFlushing
    ///
    /// @brief  Special handling of a request if issued while the HAL3Device is in the middle of a flush
    ///
    /// @param  pRequest The specific incoming request
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessRequestWhileFlushing(
        const ChiCaptureRequest* pRequest);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetDeviceInError
    ///
    /// @brief  Sets the device error status
    ///
    /// @param  isError Error status
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetDeviceInError(
        BOOL isError)
    {
        CamxAtomicStore32(&m_aDeviceInError, isError);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetDeviceInError
    ///
    /// @brief  Get the device error status
    ///
    /// @return TRUE if the device is in an error state, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL GetDeviceInError()
    {
        return static_cast<BOOL>(CamxAtomicLoad32(&m_aDeviceInError));
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetDebugBuffers
    ///
    /// @brief  Cycles any active debug buffers
    ///
    /// @param  requestId New Request ID
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetDebugBuffers(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Destroy
    ///
    /// @brief  Destroys the object
    ///
    /// @param  isForced        isForced
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Destroy(
        BOOL isForced);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Flush
    ///
    /// @brief  Flush the session
    ///
    /// @param  isForced  TRUE or FALSE
    ///
    /// @return timeout or not
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL Flush(
        BOOL isForced);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// BackupAndEmptyHALRequestQueueForFlush
    ///
    /// @brief  In case of flush, backup and empty the HAL request queue.
    ///         This is done to avoid sending queued HAL requests for processing
    ///         while we wait for the flush of the inflights requests. Once inflights
    ///         flush is complete, this backed up HAL queue is flushed using HandleFlushForHALQueueRequests.
    ///         This avoids out of order results sent to the framework.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID BackupAndEmptyHALRequestQueueForFlush();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FinalizeDeferPipeline
    ///
    /// @brief  Finalize the deferred pipeline
    ///
    /// @param  pipelineIndex        Pipeline index
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult FinalizeDeferPipeline(
        UINT32 pipelineIndex);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetIntraPipelinePerFramePool
    ///
    /// @brief  Get Frame Property/ metadata pool by pipeline ID
    ///
    /// @param  poolType    Type of the per-frame pool asked for
    /// @param  pipelineId  Pipeline ID of the property/ metadata pool want to get
    ///
    /// @return Pointer to the per frame property/metadata pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    MetadataPool* GetIntraPipelinePerFramePool(
        PoolType poolType,
        UINT     pipelineId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCurrentSequenceId
    ///
    /// @brief  Get current session sequence Id
    ///
    /// @return Current sequence id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32 GetCurrentSequenceId();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetIntraRealtimePipelineId
    ///
    /// @brief  Get intra realtime pipeline id
    ///
    /// @param  inputPipelineId   The pipeline id of pipeline which need get its intra pipeline
    /// @param  pIntraPipelineId  The result intra pipeline found
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetIntraRealtimePipelineId(
        UINT     inputPipelineId,
        UINT*    pIntraPipelineId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCurrentPipelineRequestId
    ///
    /// @brief  Get current pipeline request Id based on pipeline index
    ///
    /// @param  pipelineIndex   Pipeline index
    ///
    /// @return Current pipeline request id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT64 GetCurrentPipelineRequestId(
        UINT pipelineIndex);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsPipelineRealTime
    ///
    /// @brief  Check if pipeline is realtime
    ///
    /// @param  hPipelineDescriptor   Pipeline descriptor
    ///
    /// @return True if realtime false if not
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsPipelineRealTime(
        CHIPIPELINEHANDLE hPipelineDescriptor);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsDualCamera
    ///
    /// @brief  Check if this session is dual camera or not
    ///
    /// @return True if Session has two real time pipelines, False if not
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsDualCamera()
    {
        BOOL dualCamera = FALSE;

        if (MaxRealTimePipelines == m_numInputSensors)
        {
            dualCamera = TRUE;
        }

        return dualCamera;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpState
    ///
    /// @brief  Dumps snapshot of current state to a file
    ///
    /// @param  fd      file descriptor
    /// @param  indent  indent spaces.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpState(
        INT     fd,
        UINT32  indent);

protected:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Session
    ///
    /// @brief  Constructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    Session() = default;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~Session
    ///
    /// @brief  Destructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual ~Session();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Initialize
    ///
    /// @brief  Initialize the object after creation
    ///
    /// @param  pSessionCreateData   Create data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Initialize(
        SessionCreateData* pSessionCreateData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessResults
    ///
    /// @brief  Called by the derived node when it wants to process the results
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessResults();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleFlushForInflightRequests
    ///
    /// @brief  Called to Flush all In Flight Requets (DRQ)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleFlushForInflightRequests();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleFlushForHALQueueRequests
    ///
    /// @brief  Called to Flush all HAL Requests
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleFlushForHALQueueRequests();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessRequest
    ///
    /// @brief  Called by the derived node when it wants to process a request from the queue
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessRequest();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WaitTillAllResultsAvailable
    ///
    /// @brief  Wait till all results are available
    ///
    /// @param  useTimeOut   time out based or not.
    ///
    /// @return time out status
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL WaitTillAllResultsAvailable(
        BOOL useTimeOut);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WaitTillRequestQueueEmpty
    ///
    /// @brief  Wait till request queue is empty
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID WaitTillRequestQueueEmpty();

    BOOL                    m_aCheckResults;                                ///< Results available indicator
    JobHandle               m_hJobFamilyHandle;                             ///< Job handle for HAL3 Worker
    ThreadManager*          m_pThreadManager;                               ///< Thread Manager
    UINT                    m_numPipelines;                                 ///< Number of pipelines in the Session
    SessionPerPipelineData  m_pipelineData[MaxPipelinesPerSession];         ///< Pipeline data
    UINT                    m_numRealtimePipelines;                         ///< Number of realtime pipelines in Session
    UINT                    m_numMetadataResults;                           ///< Max number of metadata results. More than 1
                                                                            ///  meand partial metadata is enabled
    UINT                    m_realtimePipelineIds[MaxPipelinesPerSession];  ///< Pipeline Ids of all realtime pipelines
    ChiCallBacks            m_chiCallBacks;                                 ///< Callbacks made into the app by the driver
    VOID*                   m_pPrivateCbData;                               ///< Private Cb data

private:

    Session(const Session&) = delete;                               ///< Disallow the copy constructor
    Session& operator=(const Session&) = delete;                    ///< Disallow assignment operator

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NodeThreadJobFamilySessionCb
    ///
    /// @brief  Job callback function
    ///
    /// @param  pCdata Callback Data
    ///
    /// @return NULL on pointer
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static VOID* NodeThreadJobFamilySessionCb(
        VOID* pCdata);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeNewPipelines
    ///
    /// @brief  Initialize the new pipelines
    ///
    /// @param  pSessionCreateData   Create data containing new pipeline info
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult InitializeNewPipelines(
        SessionCreateData* pSessionCreateData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FinalizePipeline
    ///
    /// @brief  Finalize the new pipelines
    ///
    /// @param  pSessionCreateData   Create data containing new pipeline info
    /// @param  pipelineIndex        Pipeline index
    /// @param  enableQTimer         Qtimer flag
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult FinalizePipeline(
        SessionCreateData* pSessionCreateData,
        UINT32             pipelineIndex,
        BIT                enableQTimer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNumInputSensors
    ///
    /// @brief  Get input sensor numbers of this session
    ///
    /// @param  pSessionCreateData   Create data containing new pipeline info
    ///
    /// @return numbers of input sensor of this session
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32 GetNumInputSensors(
        SessionCreateData* pSessionCreateData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetSensorSyncMode
    ///
    /// @brief  Get multi camera sensor hardware sync mode from static metadata
    ///
    /// @param  cameraID   camera ID
    ///
    /// @return sensor sync mode
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    SensorSyncMode GetSensorSyncMode(
        UINT32 cameraID);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsUsecaseBatchingEnabled
    ///
    /// @brief  For the selected usecase is batching enabled
    ///
    /// @return TRUE if usecase batching is enabled, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsUsecaseBatchingEnabled() const
    {
        return ((m_usecaseNumBatchedFrames > 1) ? TRUE : FALSE);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InjectResult
    ///
    /// @brief  Dispatch a set of HAL3 results to the Android framework
    ///
    /// @param  type                Type of the result
    /// @param  pPayload            Payload of the result
    /// @param  frameworkFrameNum   frameworkFrameNum of the result
    /// @param  pPrivData           private data for result
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult InjectResult(
        ResultType  type,
        VOID*       pPayload,
        UINT32      frameworkFrameNum,
        VOID*       pPrivData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNotifyMessageDescriptor
    ///
    /// @brief  Gets a notify message structure
    ///
    /// @return Pointer to notify message structure
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ChiMessageDescriptor* GetNotifyMessageDescriptor()
    {
        /// @todo (CAMX-562) Handle being called from multiple contexts if need be

        ChiMessageDescriptor* pNotifyMessage;

        pNotifyMessage = &m_notifyMessages.notifyMessage[m_notifyMessages.freeIndex];

        m_notifyMessages.freeIndex = ((m_notifyMessages.freeIndex + 1) % NotificationListSize);

        return pNotifyMessage;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleErrorCb
    ///
    /// @brief  Handle Error Callback from the Topology
    ///
    /// @param  pError        Error callback payload
    /// @param  pipelineIndex Index of the pipeline which the output buffer corresponds to
    /// @param  pPrivData     Private data for result callback
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleErrorCb(
        CbPayloadError* pError,
        UINT            pipelineIndex,
        VOID*           pPrivData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleAsyncCb
    ///
    /// @brief  Handle Async callback from Topology
    ///
    /// @param  pAsync    Async callback payload
    /// @param  pPrivData Private data for result callback
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleAsyncCb(
        CbPayloadAsync* pAsync,
        VOID*           pPrivData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleSOFCb
    ///
    /// @brief  Handle SOF event callback from CSL
    ///
    /// @param  pAsync Async callback payload
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleSOFCb(
        CbPayloadSof* pAsync);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleMetadataCb
    ///
    /// @brief  Handle metadata callback from Topology
    ///
    /// @param  pMetadata Metadata callback payload
    /// @param  pPrivData Private data for result callback
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleMetadataCb(
        CbPayloadMetadata* pMetadata,
        VOID*              pPrivData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleEarlyMetadataCb
    ///
    /// @brief  Handle early metadata callback from Topology
    ///
    /// @param  pMetadata Metadata callback payload
    /// @param  pPrivData Private data for result callback
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleEarlyMetadataCb(
        CbPayloadMetadata* pMetadata,
        VOID*              pPrivData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HandleBufferCb
    ///
    /// @brief  Handle Buffer callback from Topology
    ///
    /// @param  pPayload      Buffer callback payload
    /// @param  pipelineIndex Index of the pipeline which the output buffer corresponds to
    /// @param  pPrivData     Private data for result callback
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID HandleBufferCb(
        CbPayloadBuffer* pPayload,
        UINT             pipelineIndex,
        VOID*            pPrivData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DetermineActiveStreams
    ///
    /// @brief  Method to determine active streams in the process request
    ///
    /// @param  pPipelineProcessRequestData active streams info will be written in here
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DetermineActiveStreams(
        PipelineProcessRequestData*  pPipelineProcessRequestData) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetResultHolderBySequenceId
    ///
    /// @brief  Return a result holder corresponding to a specific sequence id
    ///
    /// @param  sequenceId  Specific id for which the result holder is sought
    ///
    /// @return Pointer to ResultHolder if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ResultHolder* GetResultHolderBySequenceId(
        UINT32 sequenceId)
    {
        LightweightDoublyLinkedListNode* pNode                = m_resultHolderList.Head();
        SessionResultHolder*             pSessionResultHolder = NULL;
        ResultHolder*                    pHolder              = NULL;
        BOOL                             bFound               = FALSE;

        while (NULL != pNode)
        {
            CAMX_ASSERT(NULL != pNode->pData);
            if (NULL != pNode->pData)
            {
                pSessionResultHolder = reinterpret_cast<SessionResultHolder*>(pNode->pData);

                for (UINT32 i = 0 ; i < pSessionResultHolder->numResults; i++)
                {
                    pHolder = &pSessionResultHolder->resultHolders[i];
                    if (pHolder->sequenceId == sequenceId)
                    {
                        // Found the result holder at the sequence id we were looking for
                        // so break out of the while loop
                        bFound = TRUE;
                        break;
                    }

                }
            }
            if (TRUE == bFound)
            {
                break;
            }
            else
            {
                pHolder = NULL;
            }
            pNode = m_resultHolderList.NextNode(pNode);
        }

        return pHolder;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetFrameworkFrameNumber
    ///
    /// @brief  Return the framework's frameNumber based on sequenceId
    ///
    /// @param  sequenceId   Sequence ID for which the result holder is sought
    ///
    /// @return Framework's frameNumber
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT32 GetFrameworkFrameNumber(
        UINT32 sequenceId)
    {
        return static_cast<UINT32>(m_fwFrameNumberMap[sequenceId % MaxQueueDepth]);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessResultEarlyMetadata
    ///
    /// @brief  Processes metadata result for a given result
    ///
    /// @param  pResultHolder Sequence ID for which the result holder is sought
    /// @param  pNumResults   Current number of results
    ///
    /// @return BOOL
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL ProcessResultEarlyMetadata(
        ResultHolder* pResultHolder,
        UINT*         pNumResults);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessResultMetadata
    ///
    /// @brief  Processes metadata result for a given result
    ///
    /// @param  pResultHolder Sequence ID for which the result holder is sought
    /// @param  pNumResults   Current number of results
    ///
    /// @return BOOL
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL ProcessResultMetadata(
        ResultHolder* pResultHolder,
        UINT*         pNumResults);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessResultBuffers
    ///
    /// @brief  Processes metadata result for a given result
    ///
    /// @param  pResultHolder     Sequence ID for which the result holder is sought
    /// @param  metadataAvailable Meta available
    /// @param  pNumResults       Current number of results
    ///
    /// @return BOOL
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL ProcessResultBuffers(
        ResultHolder* pResultHolder,
        BOOL          metadataAvailable,
        UINT*         pNumResults);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetStreamIndex
    ///
    /// @brief  Return the index corresponding to the output stream passed in
    ///
    /// @param  pStream Stream for which the index is required
    ///
    /// @return The index corresponding to the output stream passed in
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT32 GetStreamIndex(
        ChiStream* pStream
        ) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// UnregisterThreadJobCallback
    ///
    /// @brief  Unregister thread job family
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual VOID UnregisterThreadJobCallback();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DispatchResults
    ///
    /// @brief  Dispatch a set of HAL3 results to the Android framework
    ///
    /// @param  pCaptureResults      The set of results to be dispatched
    /// @param  numCaptureResults    The number of results in the set
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult DispatchResults(
        ChiCaptureResult* pCaptureResults,
        UINT32            numCaptureResults) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DispatchNotify
    ///
    /// @brief  Dispatch a HAL3 notify message to the Android framework
    ///
    /// @param  pNotifyMessage The message to notify
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult DispatchNotify(
        ChiMessageDescriptor* pNotifyMessage) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ClearAllPendingItems
    ///
    /// @brief  Clear pending status of all metadata and output buffer streams for a result
    ///
    /// @param  pHolder The holder of the specific result
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ClearAllPendingItems(
        ResultHolder* pHolder
        ) const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// MeetFrameworkNotifyCriteria
    ///
    /// @brief  Decide if a result component callback warrants triggering the HAL3 Worker to process results
    ///
    /// @param  pHolder Holder for the specific result
    ///
    /// @return TRUE or FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL MeetFrameworkNotifyCriteria(
        ResultHolder* pHolder);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetResultStreamBuffer
    ///
    /// @brief  Gets a result stream buffer
    ///
    /// @return Pointer to result stream buffer
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ChiStreamBuffer* GetResultStreamBuffer()
    {
        ChiStreamBuffer* pStreamBuffer;

        pStreamBuffer                   = &m_resultStreamBuffers.resultStreamBuffer[m_resultStreamBuffers.freeIndex];
        m_resultStreamBuffers.freeIndex = ((m_resultStreamBuffers.freeIndex + 1) % OutputStreamBufferListSize);

        return pStreamBuffer;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// MetadataReadyToFly
    ///
    /// @brief  Check if a Metadata result component can be notified to the framework
    ///
    /// @param  frameworkFrameNum  Frame number to which this metadata belongs
    ///
    /// @return TRUE or FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL MetadataReadyToFly(
        UINT32 frameworkFrameNum);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// BufferReadyToFly
    ///
    /// @brief  Check if a Buffer result component can be notified to the framework
    ///
    /// @param  frameworkFrameNum   RequestId to which this buffer belongs
    /// @param  pStream             Corresponding output stream of this buffer
    ///
    /// @return TRUE or FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL BufferReadyToFly(
        UINT32     frameworkFrameNum,
        ChiStream* pStream);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AdvanceMinExpectedResult
    ///
    /// @brief  Check and advance the minimum frame number for which a result is expected
    ///
    /// @note   m_pResultLock must be acquired before entry to this function
    ///
    /// @param  flush TRUE or FALSE
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID AdvanceMinExpectedResult(
        BOOL flush);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetPerStreamColorMetadata
    ///
    /// @brief  Set color metadata for stream buffer
    ///
    /// @param  pRequest   The metadata and input/output buffers to use for the capture request.
    /// @param  pInputPool The Input MetadataPool it need get parameters
    /// @param  requestId  Request ID
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult SetPerStreamColorMetadata(
        const ChiCaptureRequest*   pRequest,
        MetadataPool*              pInputPool,
        UINT64                     requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// QueryStreamHDRMode
    ///
    /// @brief  Query the HDR mode for the stream
    ///
    /// @param  pStream    The HAL stream to query from
    /// @param  pInputPool The Input MetadataPool it need get parameters
    /// @param  requestId  Request ID for the current query
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult QueryStreamHDRMode(
        HAL3Stream*                pStream,
        MetadataPool*              pInputPool,
        UINT64                     requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsTorchWidgetSession
    ///
    /// @brief  Query whether this is Torch Widget session
    ///
    /// @return TRUE if node is Torch widget session.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsTorchWidgetSession()
    {
        return m_isTorchWidgetSession;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetPerFrameVTTimestampMetadata
    ///
    /// @brief  This function sets VT timestamp in native buffer
    ///
    /// @param  phBufferHandle native buffer handle
    /// @param  pPool          pointer to metadata pool
    /// @param  requestId      request ID
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetPerFrameVTTimestampMetadata(
        const NativeHandle* phBufferHandle,
        MetadataPool*       pPool,
        UINT64              requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetPerFrameVideoPerfModeMetadata
    ///
    /// @brief  This function sets Video perf mode in native buffer
    ///
    /// @param  phBufferHandle native buffer handle
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetPerFrameVideoPerfModeMetadata(
        const NativeHandle* phBufferHandle);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// isVideoStream
    ///
    /// @brief  Check if the stream is video stream by looking at gralloc usage
    ///
    /// @param  usage gralloc usage of the stream
    ///
    /// @return TRUE if it is video stream
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL isVideoStream(
        GrallocUsage usage)
    {
        BOOL returnVal = FALSE;
        if (0 != (GrallocUsageHwVideoEncoder & usage))
        {
            returnVal = TRUE;
        }

        return returnVal;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// isPreviewStream
    ///
    /// @brief  Check if the stream is preview stream by looking at gralloc usage
    ///
    /// @param  usage gralloc usage of the stream
    ///
    /// @return TRUE if it is preview stream
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL isPreviewStream(
        GrallocUsage usage)
    {
        BOOL returnVal = FALSE;
        if (0 != (GrallocUsageHwComposer & usage))
        {
            returnVal = TRUE;
        }

        return returnVal;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpResultState
    ///
    /// @brief  Dumps snapshot of current state to a file
    ///
    /// @param  fd      file descriptor
    /// @param  indent  indent spaces.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpResultState(
        INT     fd,
        UINT32  indent);

    UINT                   m_requestQueueDepth;                        ///< RequestQueueDepth - for batched mode its
                                                                       ///  RequestQueueDepth * MaxBatchedFrames
    ChiContext*            m_pChiContext;                              ///< Context pointer
    HAL3Queue*             m_pRequestQueue;                            ///< Input Request queue
    HAL3Queue*             m_pFlushRequestQueue;                       ///< Backed up input Request queue during flush
    Mutex*                 m_pResultLock;                              ///< Used to serialize result processing
    Mutex*                 m_pRequestLock;                             ///< Used to serialize request processing
    Mutex*                 m_pFlushLock;                               ///< Used to halt processing until requests and results
                                                                       ///  have drained
    Mutex*                 m_pStreamOnOffLock;                         ///< Used to halt requests until stream on/off complete
    volatile UINT8         m_aFlushingPipeline;                        ///< There is a wait active on draining all requests and
                                                                       ///  results.  Only freely accessed when holding
                                                                       ///  m_pFlushLock
    volatile UINT8         m_aFlushingSession;                        ///< There is a wait active on draining all requests and
                                                                      ///  results.
    BOOL                   m_inputDefaultsInitialized;                 ///< Have defaults been setup for input pool
    MetadataPool*          m_pPerFrameDebugDataPool;                   ///< Debug-data request data pool
    SessionCaptureRequest  m_captureRequest;                           ///< Capture request (that may or may not be batched)
    UINT                   m_batchedFrameIndex[MaxPipelinesPerSession];///< Running batch index
    BOOL                   m_isRequestBatchingOn;                      ///< Usecase selects whether batching *CAN* be enabled
                                                                       ///  or not in general. And we have to check per-request
                                                                       ///  to see if batching is ON or not. If batching
                                                                       ///  is ON in a request it remains ON for
                                                                       ///  m_usecaseNumBatchedFrames requests
    UINT64                 m_currentFrameCount;                        ///< Current frame count used for FPS calc
    UINT64                 m_lastFPSCountTime;                         ///< Used to calculate elapsed time
    Condition*             m_pWaitAllResultsAvailable;                 ///< Wait till all results are available
    DeferredRequestQueue*  m_pDeferredRequestQueue;                    ///< Pointer to the deferred process handler
    UINT                   m_usecaseNumBatchedFrames;                  ///< Number of framework frames batched together if
                                                                       ///  batching is enabled
    Condition*             m_pWaitLivePendingRequests;                 ///< Wait if the number of live pending requests
                                                                       ///  reaches pipeline delay
    Mutex*                 m_pLivePendingRequestsLock;                 ///< Used to block until ready to accept next
                                                                       ///  request from framework
    UINT                   m_livePendingRequests;                      ///< The number of live pending requests
    UINT                   m_maxLivePendingRequests;                   ///< The number of the maximum live pending requests
    UINT                   m_defaultMaxLivePendingRequests;            ///< The number of the default maximum live pending
                                                                       ///  requests for non-batch mode.
    LightweightDoublyLinkedList m_resultHolderList;                    ///< Result Holder list
    ChiCaptureResult*      m_pCaptureResult;                           ///< Final results to send to the Android framework
    ResultStreamBuffers    m_resultStreamBuffers;                      ///< Result stream buffers
    NotifyMessages         m_notifyMessages;                           ///< Notify messages

    /// @todo (CAMX-1797) Need to rethink about the correct place to do this
    CmdBufferManager*     m_pDebugBufferManager;                       ///< Debug buffers
    CmdBufferManager*     m_pRegDumpDebugBufferManager;                ///< Register dump debug buffers
    BOOL                  m_aFlushStatus;                              ///< Flush status of the HAL3Device
    BOOL                  m_aDeviceInError;                            ///< HAL3Device is in an error state
    MultiRequestSyncData  m_requestSyncData[MaxQueueDepth];    ///< Multi pipeline request sync information
    UINT64                m_syncSequenceId;                            ///< Multi request sequence id for sync
    UINT64                m_requestBatchId[MaxPipelinesPerSession];    ///< Running request id, incremented per batch
    UINT32                m_sequenceId;                                ///< Running counter, incremented for every Process* call
    /// @todo (CAMX-2876) The 8 limit is artificial...this should either be dynamically allocated, or create static
    ///                   const with a good max value
    UINT64                m_fwFrameNumberMap[MaxQueueDepth];   ///< Map of session request ID back to framework frame
                                                                       ///< number
    UINT32                m_vendorTagSensorModeIndex;                  ///< Index of the sensor mode vendor tag
    UINT32                m_numInputSensors;                           ///< sensor numbers of session input.
    BOOL                  m_isTorchWidgetSession;                      ///< Is torch widget session
    UINT32                m_vendorTagIndexTimestamp;                   ///< Index of the timestamp vendor tag
    JobHandle             m_hNodeJobHandle;                            ///< Job handle
    UINT32                m_videoStabilizationCaps;                    ///< EIS capabilities
    UINT32                m_recordingEndOfStreamTagId;                 ///< Recording end tag
    UINT32                m_recordingEndOfStreamRequestIdTagId;        ///< Recording end requestIDtag
    BOOL                  m_isSyncedLink;                              ///< Indicates whether linking is done or not
    BOOL                  m_setVideoPerfModeFlag;                      ///< Flag to indicate video perf mode needs to be set
    BOOL                  m_sesssionInitComplete;                      ///< To check if session initialization is complete
};

CAMX_NAMESPACE_END

#endif // CAMXSESSION_H
